package auth

import (
	"errors"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gogf/gf/frame/g"
)

type jwtType struct{}
type customClaims struct {
	user *User
	jwt.StandardClaims
}

var (
	signKey = []byte(g.Cfg().GetString(`jwt.secret`))
	expired = g.Cfg().GetInt64(`jwt.expired`)
	Jwt     = new(jwtType)
)

func keyFunc(token *jwt.Token) (interface{}, error) {
	return signKey, nil
}

func (*jwtType) parseToken(str string) (*customClaims, error) {
	token, err := jwt.ParseWithClaims(str, &customClaims{}, keyFunc)
	if err != nil {
		return nil, err
	}

	if token != nil {
		if claims, ok := token.Claims.(*customClaims); ok && claims.user != nil {
			return claims, nil
		}
	}

	return nil, errors.New(`token invalid`)
}

func (*jwtType) CreateToken(user *User) *customClaims {
	return &customClaims{
		user: user,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Unix() + expired,
		},
	}
}

// SignToken 签名
func (*jwtType) SignToken(claims *customClaims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	return token.SignedString(signKey)
}

// RefreshToken 刷新token
func (j *jwtType) RefreshToken(str string) (*customClaims, error) {
	token, err := j.parseToken(str)
	if err != nil {
		return nil, err
	}
	return j.CreateToken(token.user), nil
}

// User 获取用户信息
func (j *jwtType) User(str string) (*User, error) {
	token, err := j.parseToken(str)
	if err != nil {
		return nil, err
	}

	return token.user, nil
}
